package com.goku.gobang;

import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 人人对战游戏布局文件
 * @author goku
 */
public class ChessboardView extends View {

    /**
     * 屏幕背景
     */
    private Paint background;
    /**
     * 棋盘背景
     */
    private Paint grid;
    /**
     * 黑棋
     */
    private Paint playerOne;
    /**
     * 白棋
     */
    private Paint playerTwo;
    /**
     * 内部格网线
     */
    private Paint light;
    /**
     * 外部格网线
     */
    private Paint dark;
    /**
     * 格网宽度
     */
    private float width;
    /**
     * 格网高度
     */
    private float heigth;
    /**
     * 上下文
     */
    private Context context;
    /**
     * 格网数量
     */
    private final int SIZE = 10;
    /**
     * 格网区域
     */
    private Rect[][] rects;
    /**
     * 所下棋子种类
     */
    private boolean[][] whichPress;
    /**
     * 连接棋子个数
     */
    private int count;
    /**
     * 与放入棋子有相关性的棋子
     */
    private Point tempPoint;
    /**
     * 相关性棋子横坐标
     */
    private int tempX;
    /**
     * 相关性棋子纵坐标
     */
    private int tempY;
    /**
     * 放入的最后一颗棋子
     */
    private Point lastPoint;
    /**
     * 最后棋子横坐标
     */
    private int lastPointx;
    /**
     * 最后棋子纵坐标
     */
    private int lastPointy;
    /**
     * 点击横坐标
     */
    private int x;
    /**
     * 点击纵坐标
     */
    private int y;
    /**
     * 棋子半径比例
     */
    private float RADIUS = 0.3f;
    /**
     * 棋子坐标数组
     */
    private Point[][] points;
    /**
     * 当前坐标是否有棋子
     */
    private boolean[][] hasChess;
    /**
     * 黑棋剩余悔棋次数
     */
    private int blackCount;
    /**
     * 白棋剩余悔棋次数
     */
    private int whiteCount;
    /**
     * 判断接下来放入的棋子种类
     */
    private boolean changeChess;
    /**
     * 是否可以悔棋
     */
    private boolean iswithdraw;
    /**
     * 是否完成了悔棋
     */
    private boolean haswithdraw;
    /**
     * 是否放入棋子
     */
    private boolean isPress;
    /**
     * 点击返回按钮，onTouch不再响应
     */
    private boolean doNothing;
    /**
     * 黑棋集合
     */
    private List<Point> blackPoints;
    /**
     * 白棋集合
     */
    private List<Point> whitePoints;

    /**
     * 构造函数
     * @param context
     *            上下文
     */
    public ChessboardView(Context context) {
        super(context);
        init(context);
    }

    /**
     * 构造函数
     * @param context
     *            上下文
     * @param attrs
     *            属性
     * @param defStyle
     *            样式
     */
    public ChessboardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /**
     * 构造函数
     * @param context
     *            上下文
     * @param attrs
     *            属性
     */
    public ChessboardView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    /**
     * 初始化
     * @param context
     */
    private void init(Context context) {
        setFocusableInTouchMode(true);
        this.context = context;
        background = new Paint();
        background.setColor(Color.WHITE);
        grid = new Paint();
        grid.setColor(Color.LTGRAY);
        light = new Paint();
        light.setColor(Color.BLACK);
        dark = new Paint();
        dark.setColor(Color.BLACK);
        playerOne = new Paint();
        playerOne.setColor(Color.BLACK);
        playerOne.setStyle(Style.FILL);
        playerOne.setAntiAlias(true);
        playerTwo = new Paint();
        playerTwo.setColor(Color.WHITE);
        playerTwo.setStyle(Style.FILL);
        playerTwo.setAntiAlias(true);
        blackPoints = new ArrayList<Point>();
        whitePoints = new ArrayList<Point>();
        rects = new Rect[SIZE][SIZE];
        points = new Point[SIZE][SIZE];
        whichPress = new boolean[SIZE][SIZE];
        hasChess = new boolean[SIZE][SIZE];
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                rects[i][j] = new Rect();
                points[i][j] = new Point();
            }
        }
        assign();
    }

    /**
     * 赋值函数
     */
    public void assign() {
        blackCount = 3;
        whiteCount = 3;
        changeChess = true;
        haswithdraw = false;
        iswithdraw = false;
        isPress = false;
        doNothing = false;
        blackPoints.clear();
        whitePoints.clear();
        for (int i = 1; i < SIZE; i++) {
            for (int j = 1; j < SIZE; j++) {
                points[i][j].set(-1, -1);
                whichPress[i][j] = false;
                hasChess[i][j] = false;
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int measuredWidth = measureWidth(widthMeasureSpec);
        setMeasuredDimension(measuredWidth, measuredWidth);
    }

    private int measureWidth(int measureSpec) {
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int result = 500;
        if (specMode == MeasureSpec.AT_MOST) {
            result = specSize;
        } else if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        }
        return result;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        width = w / SIZE;
        heigth = width;
        super.onSizeChanged(w, h, oldw, oldh);
    }

    /**
     * 根据传递的坐标获取区域
     * @param i
     *            横坐标
     * @param j
     *            纵坐标
     * @param rect
     *            需要设置的选区
     */
    public void getRect(int i, int j, Rect rect) {
        rect.set((int) (i * width), (int) (j * heigth),
                (int) (i * width + width), (int) (j * heigth + heigth));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0, 0, getWidth(), getHeight(), background);
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                getRect(i, j, rects[i][j]);
                canvas.drawRect(rects[i][j], grid);
            }
        }

        for (int i = 1; i < SIZE; i++) {

            if (i == 1 || i == SIZE - 1) {
                dark.setStrokeWidth(3f);
                canvas.drawLine(width, i * heigth, getWidth() - width, i
                        * heigth, dark);
                canvas.drawLine(i * width, width, i * width,
                        getWidth() - width, dark);
            } else {

                light.setStrokeWidth(2f);
                canvas.drawLine(width, i * heigth, getWidth() - width, i
                        * heigth, light);
                canvas.drawLine(i * width, width, i * width,
                        getWidth() - width, light);
            }
        }

        if (isPress) {
            for (int i = 1; i < SIZE; i++) {
                for (int j = 1; j < SIZE; j++) {
                    if (points[i][j].equals(-1, -1)) {
                        continue;
                    }
                    if (whichPress[i][j]) {
                        canvas.drawCircle(points[i][j].x * width,
                                points[i][j].y * heigth, RADIUS * width,
                                playerOne);
                    } else {
                        canvas.drawCircle(points[i][j].x * width,
                                points[i][j].y * heigth, RADIUS * width,
                                playerTwo);
                    }
                }
            }
        }
        changeChess = !changeChess;
    }

    /**
     * 点击调用
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() != MotionEvent.ACTION_DOWN) {
            return super.onTouchEvent(event);
        }
        if (doNothing) {
            return true;
        }
        x = (int) event.getX();
        y = (int) event.getY();
        for (int i = 1; i < SIZE; i++) {
            for (int j = 1; j < SIZE; j++) {
                if (x > i * width - width / 2 && x < i * width + width / 2
                        && y > j * heigth - heigth / 2
                        && y < j * heigth + heigth / 2) {
                    if (!hasChess[i][j]) {
                        points[i][j].set(i, j);
                        whichPress[i][j] = !changeChess;
                        lastPointx = i;
                        lastPointy = j;
                        iswithdraw = true;
                        if (whichPress[i][j]) {
                            blackPoints.add(points[i][j]);
                        } else {
                            whitePoints.add(points[i][j]);
                        }
                        hasChess[i][j] = true;
                        isPress = true;
                        if (whichPress[i][j] && blackWin()) {
                            dialog(R.string.blackwin, R.string.gameover);
                        } else if (!whichPress[i][j] && whiteWin()) {
                            dialog(R.string.whitewin, R.string.gameover);
                        }
                        invalidate();
                        return true;
                    }
                }
            }
        }
        return true;
    }

    /**
     * 白棋获胜
     * @return 是否获胜
     */
    public boolean whiteWin() {
        return win(whitePoints);
    }

    /**
     * 黑棋获胜
     * @return 是否获胜
     */
    public boolean blackWin() {
        return win(blackPoints);
    }

    /**
     * 获胜
     * @param points
     *            棋子种类集合
     * @return 是否获胜
     */
    public boolean win(List<Point> points) {
        if (points.size() < 5) {
            return false;
        }
        lastPoint = points.get(points.size() - 1);
        tempPoint = new Point();
        count = 1;
        tempX = lastPoint.x - 1;
        tempY = lastPoint.y;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.x >= 1 && count < 5) {
            tempPoint.set(tempPoint.x - 1, tempY);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        tempX = lastPoint.x + 1;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.x <= SIZE - 1
                && count < 5) {
            tempPoint.set(tempPoint.x + 1, tempY);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        count = 1;
        tempX = lastPoint.x;
        tempY = lastPoint.y - 1;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.y >= 1 && count < 5) {
            tempPoint.set(tempX, tempPoint.y - 1);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        tempY = lastPoint.y + 1;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.y <= SIZE - 1
                && count < 5) {
            tempPoint.set(tempX, tempPoint.y + 1);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        count = 1;
        tempX = lastPoint.x - 1;
        tempY = lastPoint.y - 1;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.y >= 1
                && tempPoint.x >= 1 && count < 5) {
            tempPoint.set(tempPoint.x - 1, tempPoint.y - 1);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        tempX = lastPoint.x + 1;
        tempY = lastPoint.y + 1;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.y <= SIZE - 1
                && tempPoint.x <= SIZE - 1 && count < 5) {
            tempPoint.set(tempPoint.x + 1, tempPoint.y + 1);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        count = 1;
        tempX = lastPoint.x - 1;
        tempY = lastPoint.y + 1;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.y <= SIZE - 1
                && tempPoint.x >= 1 && count < 5) {
            tempPoint.set(tempPoint.x - 1, tempPoint.y + 1);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        tempX = lastPoint.x + 1;
        tempY = lastPoint.y - 1;
        tempPoint.set(tempX, tempY);
        while (points.contains(tempPoint) && tempPoint.y >= 1
                && tempPoint.x <= SIZE - 1 && count < 5) {
            tempPoint.set(tempPoint.x + 1, tempPoint.y - 1);
            count++;
        }
        if (count >= 5) {
            return true;
        }
        return false;
    }

    /**
     * 获胜对话框函数
     * @param which
     *            获胜棋子
     * @param gameover
     *            游戏结束
     */
    protected void dialog(int which, int gameover) {
        AlertDialog.Builder builder = new Builder(context);
        builder.setMessage(which);
        builder.setTitle(gameover);
        builder.setCancelable(false);
        builder.setPositiveButton(R.string.restart,
                new android.content.DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        assign();
                        invalidate();
                    }
                });
        builder.setNegativeButton(R.string.cancel,
                new android.content.DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                        doNothing = true;
                    }
                });
        builder.create().show();
    }

    public boolean getChangeChess() {
        return changeChess;
    }

    public void setChangeChess(boolean changeChess) {
        this.changeChess = changeChess;
    }

    public List<Point> getBlackPoints() {
        return blackPoints;
    }

    public void setBlackPoints(List<Point> blackPoints) {
        this.blackPoints = blackPoints;
    }

    public List<Point> getWhitePoints() {
        return whitePoints;
    }

    public void setWhitePoints(List<Point> whitePoints) {
        this.whitePoints = whitePoints;
    }

    public int getLastPointx() {
        return lastPointx;
    }

    public void setLastPointx(int lastPointx) {
        this.lastPointx = lastPointx;
    }

    public int getLastPointy() {
        return lastPointy;
    }

    public void setLastPointy(int lastPointy) {
        this.lastPointy = lastPointy;
    }

    public boolean getWhichPress(int i, int j) {
        return whichPress[i][j];
    }

    public void setWhichPress(boolean[][] whichPress) {
        this.whichPress = whichPress;
    }

    public int getBlackCount() {
        return blackCount;
    }

    public void setBlackCount(int blackCount) {
        this.blackCount = blackCount;
    }

    public int getWhiteCount() {
        return whiteCount;
    }

    public void setWhiteCount(int whiteCount) {
        this.whiteCount = whiteCount;
    }

    public boolean isHaswithdraw() {
        return haswithdraw;
    }

    public void setHaswithdraw(boolean haswithdraw) {
        this.haswithdraw = haswithdraw;
    }

    public boolean isIswithdraw() {
        return iswithdraw;
    }

    public void setIswithdraw(boolean iswithdraw) {
        this.iswithdraw = iswithdraw;
    }

    /**
     * 悔棋函数
     * @param currentPoints
     *            当前要悔的棋子
     * @param lastPoints
     *            悔棋前已放入的另一方棋子
     * @param whichpress
     *            最后放入的棋子种类
     * @param change
     *            判断接下来放入的棋子种类
     * @param withDrawCount
     *            剩余悔棋次数
     */
    public void withDraw(List<Point> currentPoints, List<Point> lastPoints,
            boolean whichpress, boolean change, int withDrawCount) {
        if (currentPoints.size() >= 1 && iswithdraw && isPress && !blackWin()
                && !whiteWin()) {
            hasChess[currentPoints.get(currentPoints.size() - 1).x][currentPoints
                    .get(currentPoints.size() - 1).y] = false;
            points[currentPoints.get(currentPoints.size() - 1).x][currentPoints
                    .get(currentPoints.size() - 1).y].set(-1, -1);
            currentPoints.remove(currentPoints.size() - 1);
            if (whichpress) {
                hasChess[lastPoints.get(lastPoints.size() - 1).x][lastPoints
                        .get(lastPoints.size() - 1).y] = false;
                points[lastPoints.get(lastPoints.size() - 1).x][lastPoints
                        .get(lastPoints.size() - 1).y].set(-1, -1);
                lastPoints.remove(lastPoints.size() - 1);
            }
            changeChess = change;
            iswithdraw = false;
            withDrawCount--;
            if (change) {
                blackCount = withDrawCount;
            } else {
                whiteCount = withDrawCount;
            }
            invalidate();
            haswithdraw = true;
        }
    }
}
